<?php

namespace IDock\Insurance\ZYIC;

use IDock\Common\BaseInterface\BuilderInterface;
use IDock\Http\Request;
use IDock\Http\Response;
use IDock\Insurance\ZYIC\Request\AllZYICRequest;
use IDock\Insurance\ZYIC\Response\AllZYICResponse;

class Builder implements BuilderInterface
{

    public function getConfig(): array
    {
        return $this->config;
    }

    protected $config;

    protected $partnerAccountCode;

    protected $recordCode;

    protected $agreementNo;

    protected $tokenUrl;

    protected $publicKey;
    protected $privateKey;

    protected $nonCarGateway;
    protected $appKey;

    protected $channelCode;

    public $token;
    public $systemFlag;
    public $planName;

    public $notifyUrl;

    public function execute(Request $request): Response
    {
        /*** @var AllZYICRequest $request */
        $request->loadConfig($this->config);

        $request->setRequestId(md5(uniqid()));
        //if(property_exists($request,'planName')){
        //    $request->planName = $this->planName;
        //}
        if(property_exists($request,'systemFlag')){
            $request->systemFlag = $this->systemFlag;
        }
        if(property_exists($request,'channelCode')){
            $request->channelCode = $this->channelCode;
        }
        $data = $this->generate($request);
        $request->setHeaders(['Content-Type' => 'application/json;charset=UTF-8']);
        $request->setPreParameter(json_encode($data,320));
        $request->setBizParam(json_encode($data,320));
        //非车请求
        if(property_exists($request,'serviceName')){
            $request->setGateway($this->nonCarGateway);
            $param = [
                'appKey' => $this->appKey,
                'timestamp' => strval(time()),
                'serviceName' => $request->serviceName,
                'version' => '1.0.0',
                'bizContent' => $this->generate($request)
            ];
            $request->setPreParameter($param);
            $this->encrypt($request);
            $this->sign($request);
        }
        return $this->request($request);
    }

    public function generate(Request $request): array
    {
        return $request->generate();
    }

    public function sign(Request $request): Request
    {
        $biz = $request->getBizParam() ?? [];
        ksort($biz);
        $biz['signValue'] = md5(json_encode($biz,320));
        $request->setBizParam(json_encode($biz,320));
        return $request;
    }

    public function exceptionResponse($request, $errorMessage): Response
    {
        $response = $request->getResponse();

        $response = new $response;
        $response->setCode('500');
        $response->setError($errorMessage);

        return $response;
    }

    public function request(Request $request): Response
    {
        /*** @var AllZYICResponse $response */
        $response = $request->request($request);
        $response->setVisitor($request->getVisitor());

        if ($response->isSuccess()) {
            if(property_exists($request,'serviceName')){
                $response->decrypt($this->formatKey($this->privateKey,'private'),$request);
            }
            $response->printerInit();
        }
        return $response;
    }

    public function encrypt(Request $request)
    {
        $publicKey = $this->formatKey($this->publicKey);
        $publicKey = openssl_get_publickey($publicKey);
        $data = $request->getPreParameter();
        $biz = $data['bizContent'] ?? '';
        $out = '';
        foreach (str_split(json_encode($biz,320),117) as $value){
            $res = openssl_public_encrypt($value,$ciphertext,$publicKey);
            if(!$res){
                throw new \Exception("加密失败");
            }
            $out .= $ciphertext;
        }
        $data['bizContent'] = base64_encode($out);
        $request->setBizParam($data);
    }

    private function formatKey($key,$type='public')
    {
        if(empty($key)){
            throw new \Exception("请配置秘钥");
        }
        if($type == 'public'){
            $keyPem = chunk_split($key, 64, "\n");
            $keyPem = "-----BEGIN PUBLIC KEY-----\n" . $keyPem . "-----END PUBLIC KEY-----\n";
        }else{
            $keyPem = chunk_split($key, 64, "\n");
            $keyPem = "-----BEGIN RSA PRIVATE KEY-----".PHP_EOL . $keyPem . "-----END RSA PRIVATE KEY-----".PHP_EOL;
        }
        return $keyPem;
    }

    public function setToken($token)
    {
        $this->token = $token;
    }
}


